﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Acl.Excel;

using NPOI.SS.UserModel;

namespace Acl.Data.RowWriters
{
    internal class ExcelRowWriter : IRowWriter
    {
        private readonly ISheet _worksheet;
        private readonly int _startColumnIndex;
        private readonly bool _includeHeader;
        private int _currentRowIndex;
        private readonly ICellStyle _headerStyle;
        private readonly ICellStyle _contentStyle;

        public string Name { get; private set; }

        public ExcelRowWriter(string fileName, ISheet worksheet, uint startRowNumber, uint startColumnNumber, bool includeHeader)
        {
            Name = fileName + ":" + worksheet.SheetName;
            _worksheet = worksheet;
            _currentRowIndex = (int)(startRowNumber - 1);
            _startColumnIndex = (int)(startColumnNumber - 1);
            _includeHeader = includeHeader;
            if (includeHeader)
                _headerStyle = Workbook.GetCellStyle(worksheet.Workbook, 2);
            _contentStyle = Workbook.GetCellStyle(worksheet.Workbook, 0);
        }

        private int _index = 0;

        public void Write(IList<object> row)
        {
            var isHeaderRow = _index == 0 && _includeHeader;
            ICellStyle style = isHeaderRow ? _headerStyle : _contentStyle;

#if DEBUG
            try
            {
#endif
            var xlsRow = _worksheet.GetRow(_currentRowIndex) ?? _worksheet.CreateRow(_currentRowIndex);
            for (int i = 0; i < row.Count; i++)
            {
                var xlsCell = xlsRow.GetCell(_startColumnIndex + i) ?? xlsRow.CreateCell(_startColumnIndex + i);
                var cellValue = row[i];
                xlsCell.CellStyle = style;
                SetCellValue(xlsCell, cellValue);
                SetColumnWidth(isHeaderRow, cellValue, xlsCell);
            }

            _currentRowIndex++;
            _index++;
#if DEBUG
            }
            catch
            {
                throw;
            }
#endif
        }

        private void SetColumnWidth(bool isHeaderRow, object cellValue, ICell xlsCell)
        {
            var strValue = cellValue != null ? cellValue.ToString() : "";
            if (isHeaderRow)
            {
                _worksheet.SetColumnWidth(xlsCell.ColumnIndex, (strValue.Length + 5) * 256);
            }
            else
            {
                //根据单元格内容设定列宽
                int length = Math.Min(255, Encoding.UTF8.GetBytes(strValue).Length + 3) * 256;
                if (_worksheet.GetColumnWidth(xlsCell.ColumnIndex) < length && !string.IsNullOrEmpty(strValue))
                {
                    _worksheet.SetColumnWidth(xlsCell.ColumnIndex, length);
                }
            }
        }

        private static readonly Type[] _boolTypes = new[] { typeof(bool), typeof(bool?) };

        private static readonly Type[] _doubleTypes = new[]
        {
            typeof(sbyte), typeof(sbyte?),
            typeof(short), typeof(short?),
            typeof(int), typeof(int?),
            typeof(long), typeof(long?),
            typeof(byte), typeof(byte?),
            typeof(ushort), typeof(ushort?),
            typeof(uint), typeof(uint?),
            typeof(ulong), typeof(ulong?),
            typeof(float), typeof(float?),
            typeof(double), typeof(double?),
            typeof(decimal), typeof(decimal?)
        };

        private void SetCellValue(ICell cell, object value)
        {
            if (value == null)
                return;
            var type = value.GetType();

            if (type == typeof(string))
                cell.SetCellValue((string)value);
            else if (_boolTypes.Contains(type))
                cell.SetCellValue((bool)value);
            else if (_doubleTypes.Contains(type))
                cell.SetCellValue(Convert.ToDouble(value));
            else
                cell.SetCellValue(value.ToString());
        }
    }
}